﻿namespace Utilities
{
    using System;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Summary description for CacheUnitTest
    /// </summary>
    [TestClass]
    public class CacheUnitTest
    {
        readonly Random r = new Random();
        private readonly LruCache<int, string> lruCache = new LruCache<int, string>(new TimeSpan(0, 0, 0, 10));

        [TestMethod]
        public void TestSizeBasedCache()
        {
            LruCache<int, string> cache = new LruCache<int, string>(TimeSpan.MaxValue, 3);
            cache.AddObject(1, "One");
            cache.AddObject(2, "Two");
            cache.AddObject(3, "Three");

            ////insert one more, which will kick 1 out
            cache.AddObject(4, "Four");

            ////check if 1 is kicked out
            Assert.IsNull(cache.GetObject(1));

            ////check if 2 is still there
            Assert.AreEqual(cache.GetObject(2), "Two");
        }

        [TestMethod]
        public void TestTimeBasedCache()
        {
            LruCache<int, string> cache = new LruCache<int, string>(new TimeSpan(0, 0, 0, 5), uint.MaxValue);
            cache.AddObject(2, "Two");

            ////check if object is there after 2 seconds (not expired)
            Thread.Sleep(2000);
            Assert.AreEqual(cache.GetObject(2), "Two");

            ////check if object is there after 6 seconds (object expired)
            Thread.Sleep(4000);
            Assert.IsNull(cache.GetObject(2));
        }

        [TestMethod]
        public void TestMultithreading()
        {
            for (int i = 0; i < 10000; i++)
            {
                ThreadPool.QueueUserWorkItem(this.r.Next(100) % 10 == 0
                                             ? new WaitCallback(this.AddItem)
                                             : new WaitCallback(this.GetItem));
            }

            Thread.Sleep(4000);
        }

        private void AddItem(object stateinfo)
        {
            this.lruCache.AddObject(this.r.Next(100), this.r.Next(100).ToString());
        }

        private void GetItem(object stateinfo)
        {
            this.lruCache.GetObject(this.r.Next(100));
        }
    }
}
